#ifndef STRBLOB_H
#define STRBLOB_H

#include <string>
#include <vector>
#include <memory>
#include <stdexcept>
#include <initializer_list>
/**
 * @brief 
 * 
 */
class StrBlobPtr;
class StrBlob
{
    friend class StrBlobPtr;
public:
    typedef std::vector<std::string>::size_type size_type;
    StrBlob();
    StrBlob(std::initializer_list<std::string> il);
    size_type size() const { return data->size(); }
    bool empty() const { return data->empty(); }
    // 添加和删除元素
    void push_back(const std::string &t) { data->push_back(t); }
    void pop_back();
    // 元素访问
    std::string& front();
    const std::string &front() const;
    std::string& back();
    const std::string& back() const;
private:
    std::shared_ptr<std::vector<std::string>> data;
    // 如果data[i]不合法，抛出一个异常
    void check(size_type i, const std::string &msg) const;
    StrBlobPtr begin() { return StrBlobPtr(*this); }
    StrBlobPtr end() 
    { 
        auto ret = StrBlobPtr(*this, data->size());   
        return ret;  
    }
};
/**
 * @brief Construct a new Str Blob:: Str Blob object
 * 
 */
StrBlob::StrBlob(): data(std::make_shared<std::vector<std::string>>()) { }
/**
 * @brief Construct a new Str Blob:: Str Blob object
 * 
 * @param il 
 */
StrBlob::StrBlob(std::initializer_list<std::string> il) : data(std::make_shared<std::vector<std::string>>(il)) { }
/**
 * @brief 检查给定的索引是否在合法范围内，如果不合法，抛出异常
 * 
 * @param i 
 * @param msg 
 */
void StrBlob::check(size_type i, const std::string &msg) const
{
    if(i >= data->size())
    {
        throw std::out_of_range(msg);
    }
}
/**
 * @brief 
 * 
 * @return std::string& 
 */
std::string& StrBlob::front()
{
    // 如果 vector 为空,check 会抛出一个异常
    check(0, "fornt on empty StrBlob");
    return data->front();
}
/**
 * @brief 
 * 
 * @return const std::string& 
 */
const std::string& StrBlob::front() const
{
    check(0, "fornt on empty StrBlob");
    return data->front();
}
/**
 * @brief 
 * 
 * @return std::string& 
 */
std::string& StrBlob::back()
{
    check(0, "back on empty StrBlob");
    return data->back();
}
/**
 * @brief 
 * 
 * @return const std::string& 
 */
const std::string& StrBlob::back() const
{
    check(0, "back on empty StrBlob");
    return data->back();
}
/**
 * @brief 
 * 
 */
void StrBlob::pop_back()
{
    check(0, "pop_back on empty StrBlob");
    data->pop_back();
}

#endif